var socket;

Vue.component("footer-player", {
  template: "#footer-player",
});

// vue instance
var app = new Vue({
  el: "#app",
  data: {
    screen: "player",
    player: {
      currentMediaItem: {},
      songActions: false,
      maxVolume: 1,
      lyrics: {},
      lyricsMediaItem: {},
      lyricsDebug: {
        current: 0,
        start: 0,
        end: 0,
      },
      lyricsScrollingBlocked: false,
      queue: {},
      lowerPanelState: "controls",
      userInteraction: false,
      status: {
        inLibrary: false,
        rating: 0,
      },
    },
    queue: {
      temp: [],
    },
    artistPage: {
      data: {},
      editorsNotes: false,
    },
    albumPage: {
      data: {},
      editorsNotes: false,
    },
    search: {
      query: "",
      results: [],
      state: 0,
      tab: "all",
      searchType: "applemusic",
      trackSelect: false,
      selected: {},
      queue: {},
      lastPage: "search",
      lastY: 0,
    },
    lastPage: "player",
    connectedState: 0,
    url: window.location.hostname,
    mode: "default",
    // url: "localhost",
  },
  methods: {
    isElectron() {
      // Renderer process
      if (typeof window !== "undefined" && typeof window.process === "object" && window.process.type === "renderer") {
        return true;
      }
      // Main process
      if (typeof process !== "undefined" && typeof process.versions === "object" && !!process.versions.electron) {
        return true;
      }
      // Detect the user agent when the `nodeIntegration` option is set to true
      if (typeof navigator === "object" && typeof navigator.userAgent === "string" && navigator.userAgent.indexOf("Electron") >= 0) {
        return true;
      }
      return false;
    },
    searchScroll(e) {
      this.search.lastY = e.target.scrollTop;
    },
    musicKitAPI(method, id, params, library = false) {
      socket.send(
        JSON.stringify({
          action: "musickit-api",
          method: method,
          id: id,
          params: params,
          library: library,
        }),
      );
    },
    resetPlayerUI() {
      this.player.lowerPanelState = "controls";
    },
    musicAppVariant() {
      if (navigator.userAgent.match(/Android/i)) {
        return "Cider";
      } else if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
        return "Cider";
      } else {
        if (navigator.userAgent.indexOf("Mac") > 0) {
          return "Music";
        } else if (navigator.userAgent.indexOf("Win") > 0) {
          return "Cider";
        } else {
          return "Cider";
        }
      }
    },
    checkOrientation() {
      // check orientation of device
      if (window.innerHeight > window.innerWidth) {
        return "portrait";
      } else {
        return "landscape";
      }
    },
    checkPlatformMD() {
      // check if platfom is desktop or mobile
      if (navigator.userAgent.match(/Android/i)) {
        return "mobile";
      } else if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
        return "mobile";
      } else {
        if (navigator.userAgent.indexOf("Mac") > 0) {
          return "desktop";
        } else if (navigator.userAgent.indexOf("Win") > 0) {
          return "desktop";
        } else {
          return "desktop";
        }
      }
    },
    checkPlatform() {
      if (navigator.userAgent.match(/Android/i)) {
        return "android";
      } else if (navigator.userAgent.match(/iPhone|iPad|iPod/i)) {
        return "ios";
      } else {
        if (navigator.userAgent.indexOf("Mac") > 0) {
          return "mac";
        } else if (navigator.userAgent.indexOf("Win") > 0) {
          return "win";
        } else {
          return "linux";
        }
      }
    },
    artworkPlaying() {
      if (this.player.currentMediaItem.status) {
        return;
      } else {
        return ["paused"];
      }
    },
    setAutoplay(value) {
      socket.send(
        JSON.stringify({
          action: "set-autoplay",
          autoplay: value,
        }),
      );
      this.getCurrentMediaItem();
      if (value) {
        setTimeout(() => {
          this.getQueue();
        }, 1000);
      } else {
        this.getQueue();
      }
    },
    seekTo(time, adjust = true) {
      if (adjust) {
        time = parseInt(time / 1000);
      }
      socket.send(
        JSON.stringify({
          action: "seek",
          time: time,
        }),
      );
    },
    setVolume(volume) {
      socket.send(
        JSON.stringify({
          action: "volume",
          volume: volume,
        }),
      );
    },
    getVolumeMax() {
      socket.send(
        JSON.stringify({
          action: "volumeMax",
        }),
      );
    },
    getQueue() {
      socket.send(
        JSON.stringify({
          action: "get-queue",
        }),
      );
    },
    play() {
      socket.send(
        JSON.stringify({
          action: "play",
        }),
      );
    },
    pause() {
      socket.send(
        JSON.stringify({
          action: "pause",
        }),
      );
    },
    next() {
      socket.send(
        JSON.stringify({
          action: "next",
        }),
      );
    },
    previous() {
      socket.send(
        JSON.stringify({
          action: "previous",
        }),
      );
    },
    searchArtist() {
      this.search.query = this.player.currentMediaItem.artistName;
      this.screen = "search";
      this.searchQuery();
    },
    trackSelect(song) {
      this.search.selected = song;
      this.search.trackSelect = true;
    },
    clearSelectedTrack() {
      this.search.selected = {};
      this.search.trackSelect = false;
    },
    getArtworkColor(hex) {
      return `#${hex}`;
    },
    playMediaItemById(id, kind = "song") {
      socket.send(
        JSON.stringify({
          action: "play-mediaitem",
          id: id,
          kind: kind,
        }),
      );
      this.screen = "player";
    },
    playNext(type, id) {
      socket.send(
        JSON.stringify({
          action: "play-next",
          type: type,
          id: id,
        }),
      );
    },
    playLater(type, id) {
      socket.send(
        JSON.stringify({
          action: "play-later",
          type: type,
          id: id,
        }),
      );
    },
    getLibraryStatus(type, id) {
      if (type !== undefined && id !== "no-id-found") {
        socket.send(
          JSON.stringify({
            action: "library-status",
            type: type,
            id: id,
          }),
        );
      } else {
        this.player.status = {};
      }
    },
    searchQuery() {
      if (this.search.query.length == 0) {
        this.search.state = 0;
        return;
      }
      this.search.state = 1;
      var actionType = "search";
      if (this.search.searchType == "library") {
        actionType = "library-search";
      }
      socket.send(
        JSON.stringify({
          action: actionType,
          term: this.search.query,
          limit: 20,
        }),
      );
    },
    quickSearch() {
      var search = prompt("Search for a song", "");
      if (search == null || search == "") {
        return;
      }

      socket.send(
        JSON.stringify({
          action: "quick-play",
          term: search,
        }),
      );
    },
    parseTime(value) {
      var minutes = Math.floor(value / 60000);
      var seconds = ((value % 60000) / 1000).toFixed(0);
      return minutes + ":" + (seconds < 10 ? "0" : "") + seconds;
    },
    parseTimeDecimal(value) {
      var minutes = Math.floor(value / 60000);
      var seconds = ((value % 60000) / 1000).toFixed(0);
      return minutes + "." + (seconds < 10 ? "0" : "") + seconds;
    },
    hmsToSecondsOnly(str) {
      var p = str.split(":"),
        s = 0,
        m = 1;

      while (p.length > 0) {
        s += m * parseInt(p.pop(), 10);
        m *= 60;
      }

      return s;
    },
    getCurrentTime() {
      return parseFloat(this.hmsToSecondsOnly(this.parseTime(this.player.currentMediaItem.durationInMillis - this.player.currentMediaItem.remainingTime)));
    },
    percentage(partial, full) {
      return (100 * partial) / full;
    },
    getLyricBGStyle(start, end) {
      var currentTime = this.getCurrentTime();
      var duration = this.player.currentMediaItem.durationInMillis;
      var start2 = this.hmsToSecondsOnly(start);
      var end2 = this.hmsToSecondsOnly(end);
      var currentProgress = (100 * currentTime) / end2;
      // check if currenttime is between start and end
      this.player.lyricsDebug.start = start2;
      this.player.lyricsDebug.end = end2;
      this.player.lyricsDebug.current = currentTime;
      if (currentTime >= start2 && currentTime <= end2) {
        return {
          "--bgSpeed": `${end2 - start2}s`,
        };
      } else {
        return {};
      }
    },
    blockLyricsScrolling() {
      this.lyricsScrollingBlocked = true;
      setTimeout(() => {
        this.lyricsScrollingBlocked = false;
      }, 100);
    },
    getLyricClass(start, end) {
      var currentTime = this.getCurrentTime();
      // check if currenttime is between start and end
      if (currentTime >= start && currentTime <= end) {
        setTimeout(() => {
          if (document.querySelector(".lyric-line.active") && !this.lyricsScrollingBlocked) {
            document.querySelector(".lyric-line.active").scrollIntoView({
              behavior: "smooth",
              block: "center",
            });
          }
        }, 200);
        return "active";
      } else {
        return "";
      }
    },
    getAlbumArtUrl(size = 600) {
      if (this.player.currentMediaItem.artwork) {
        return `url("${this.player.currentMediaItem.artwork.url.replace("{w}", size).replace("{h}", size)}")`;
      } else {
        return "";
      }
    },
    getAlbumArtUrlList(url, size = 64) {
      return `url("${url.replace("{w}", size).replace("{h}", size)}")`;
    },
    searchTabClass(tab) {
      if (tab == this.search.tab) {
        return "active";
      }
    },
    searchTypeClass(type) {
      if (type == this.search.searchType) {
        return "active";
      }
    },
    getQueuePositionClass(position) {
      if (this.player.queue["_position"] == position) {
        return ["playing", "passed"];
      } else if (this.player.queue["_position"] > position) {
        return ["passed"];
      }
    },
    showSearch(reset = false) {
      if (reset) {
        this.search.lastPage = "search";
      }
      switch (this.search.lastPage) {
        case "search":
          this.screen = "search";
          break;
        case "album":
          this.screen = "album-page";
          break;
        case "artist":
          this.screen = "artist-page";
          break;
        case "playlist":
          this.screen = "playlist-page";
          break;
      }
    },
    showArtistByName(name) {
      this.musicKitAPI("search", name, { types: "artists" });
    },
    showAlbum(id, library = false) {
      this.search.lastPage = "album";
      this.screen = "album-page";
      this.musicKitAPI("album", id, {}, library);
    },
    showPlaylist(id, library = false) {
      this.search.lastPage = "album";
      this.screen = "album-page";
      this.musicKitAPI("playlist", id, {}, library);
    },
    showArtist(id, library = false) {
      this.search.lastPage = "artist";
      this.screen = "artist-page";
      this.musicKitAPI("artist", id, { include: "songs,playlists,albums" }, library);
    },
    showQueue() {
      this.queue.temp = this.player["queue"]["_queueItems"];
      this.screen = "queue";
      this.getQueue();
    },
    queueMove(evt) {
      // console.log(evt)
      // console.log(`new: ${evt.moved.newIndex} old: ${evt.moved.oldIndex}`)
      this.queue.temp.splice(evt.moved.newIndex, 0, this.queue.temp.splice(evt.moved.oldIndex, 1)[0]);
      socket.send(
        JSON.stringify({
          action: "queue-move",
          from: evt.moved.oldIndex,
          to: evt.moved.newIndex,
        }),
      );
      this.getQueue();
      return true;
    },
    repeat() {
      socket.send(
        JSON.stringify({
          action: "repeat",
        }),
      );
      this.getCurrentMediaItem();
    },
    shuffle() {
      socket.send(
        JSON.stringify({
          action: "shuffle",
        }),
      );
      this.getCurrentMediaItem();
    },
    setShuffle(val) {
      socket.send(
        JSON.stringify({
          action: "set-shuffle",
          shuffle: val,
        }),
      );
      this.getCurrentMediaItem();
    },
    getMediaPalette(data) {
      if (data != null && data["artwork"] != null) {
        var palette = {
          "--bgColor": `#${data["artwork"]["bgColor"] ?? "000000"}`,
          "--textColor1": `#${data["artwork"]["textColor1"] ?? "ffffff"}`,
          "--textColor2": `#${data["artwork"]["textColor2"] ?? "ffffff"}`,
          "--textColor3": `#${data["artwork"]["textColor3"] ?? "ffffff"}`,
          "--textColor4": `#${data["artwork"]["textColor4"] ?? "ffffff"}`,
        };
        return palette;
      } else {
        let u = {
          "--bgColor": `#${"000000"}`,
          "--textColor1": `#${"ffffff"}`,
          "--textColor2": `#${"ffffff"}`,
          "--textColor3": `#${"ffffff"}`,
          "--textColor4": `#${"ffffff"}`,
        };
        return u;
      }
    },
    playAlbum(id, shuffle = false) {
      if (shuffle) {
        this.setShuffle(true);
      } else {
        this.setShuffle(false);
      }
      this.playMediaItemById(id, "album");
    },
    playCustom(id, kind, shuffle = false) {
      if (shuffle) {
        this.setShuffle(true);
      } else {
        this.setShuffle(false);
      }
      this.playMediaItemById(id, kind);
    },
    getLyrics() {
      socket.send(
        JSON.stringify({
          action: "get-lyrics",
        }),
      );
    },
    showLyrics() {
      this.getLyrics();
      this.screen = "lyrics";
    },
    showLyricsInline() {
      this.getLyrics();
      this.player.lowerPanelState = "lyrics";
    },
    parseLyrics() {
      var xml = this.stringToXml(this.player.lyricsMediaItem.ttml);
      var json = xmlToJson(xml);
      this.player.lyrics = json;
    },
    stringToXml(st) {
      // string to xml
      var xml = new DOMParser().parseFromString(st, "text/xml");
      return xml;
    },
    canShowSearchTab(tab) {
      if (tab == this.search.tab || this.search.tab == "all") {
        return true;
      } else {
        return false;
      }
    },
    getCurrentMediaItem() {
      socket.send(
        JSON.stringify({
          action: "get-currentmediaitem",
        }),
      );
    },
    setStreamerOverlay() {
      document.body.classList.add("streamer-overlay");
    },
    setMode(mode) {
      switch (mode) {
        default:
          this.screen = "player";
          break;
        case "miniplayer":
          this.screen = "miniplayer";
          break;
      }
    },
    connect() {
      let self = this;
      this.connectedState = 0;
      if (this.url === "") {
        this.url = prompt("Host IP", "localhost");
      }
      socket = new WebSocket(`ws://${this.url}:26369`);
      socket.onopen = (e) => {
        console.log(e);
        console.log("connected");
        app.connectedState = 1;
        if (getParameterByName("mode")) {
          self.setMode(getParameterByName("mode"));
        } else {
          self.setMode("default");
        }
        self.clearSelectedTrack();
      };

      socket.onclose = (e) => {
        console.log(e);
        console.log("disconnected");
        app.connectedState = 2;
      };

      socket.onerror = (e) => {
        console.log(e);
        console.log("error");
        app.connectedState = 2;
      };

      socket.onmessage = (e) => {
        const response = JSON.parse(e.data);
        switch (response.type) {
          default:
            break;
          case "musickitapi.search":
            self.showArtist(response.data["artists"][0]["id"]);
            break;
          case "musickitapi.playlist":
          case "musickitapi.album":
            if (self.screen == "album-page") {
              self.albumPage.data = response.data;
            }
            break;
          case "musickitapi.artist":
            if (self.screen == "artist-page") {
              self.artistPage.data = response.data;
            }
            break;
          case "queue":
            // console.log(response.data);
            self.player.queue = response.data;
            self.queue.temp = response.data["_queueItems"];
            self.$forceUpdate();
            break;
          case "lyrics":
            self.player.lyrics = response.data;
            self.$forceUpdate();
            break;
          case "searchResultsLibrary":
            self.search.results = response.data;
            self.search.state = 2;
            break;
          case "searchResults":
            self.search.results = response.data;
            self.search.state = 2;
            break;
          case "playbackStateUpdate":
            if (!self.player.userInteraction) {
              self.updatePlaybackState(response.data);
            }
            break;
          case "maxVolume":
            this.player.maxVolume = response.data;
            break;
          case "libraryStatus":
            this.player.status = response.data;
            break;
          case "rate":
            var params = this.player.currentMediaItem.playParams;
            if (params && params.id === response.data.id && params.kind === response.data.kind) {
              this.player.status = {
                rating: response.data.rating,
                inLibrary: this.player.status.inLibrary,
              };
            }
            break;
          case "change-library":
            var params = this.player.currentMediaItem.playParams;
            if (params && params.id === response.data.id && params.kind === response.data.kind) {
              this.player.status = {
                rating: this.player.status.rating,
                inLibrary: response.data.add,
              };
            }
            break;
        }
        // console.log(e.data);
      };
    },
    updatePlaybackState(mediaitem) {
      var lyricsDisplayed = this.screen == "lyrics" || this.player.lowerPanelState == "lyrics";
      if (this.player.currentMediaItem["isrc"] != mediaitem["isrc"]) {
        this.getLibraryStatus(mediaitem.playParams.kind, mediaitem.playParams.id);

        if (lyricsDisplayed) {
          this.getLyrics();
        }
        if (this.screen == "queue") {
          this.getQueue();
        }
      }
      this.player.currentMediaItem = mediaitem;
    },
    openSongMenu() {
      const params = this.player.currentMediaItem.playParams;

      if (params) {
        this.getLibraryStatus(params.kind, params.id);
      }

      this.player.songActions = true;
    },
    rate(rating) {
      const params = this.player.currentMediaItem.playParams;

      if (params && params.kind !== undefined && params.id !== "no-id-found") {
        socket.send(
          JSON.stringify({
            action: "rating",
            type: params.kind,
            id: params.id,
            rating: rating,
          }),
        );
      }
    },
    toLibrary(shouldAdd) {
      const params = this.player.currentMediaItem.playParams;

      if (params && params.kind !== undefined && params.id !== "no-id-found") {
        socket.send(
          JSON.stringify({
            action: "change-library",
            type: params.kind,
            id: params.id,
            add: shouldAdd,
          }),
        );
      }
    },
    quit() {
      socket.send(
        JSON.stringify({
          action: "quit",
        }),
      );
    },
  },
});

function getParameterByName(name, url) {
  if (!url) url = window.location.href;
  name = name.replace(/[\[\]]/g, "\\$&");
  var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
    results = regex.exec(url);
  if (!results) return null;
  if (!results[2]) return "";
  return decodeURIComponent(results[2].replace(/\+/g, " "));
}

function xmlToJson(xml) {
  // Create the return object
  var obj = {};

  if (xml.nodeType == 1) {
    // element
    // do attributes
    if (xml.attributes.length > 0) {
      obj["@attributes"] = {};
      for (var j = 0; j < xml.attributes.length; j++) {
        var attribute = xml.attributes.item(j);
        obj["@attributes"][attribute.nodeName] = attribute.nodeValue;
      }
    }
  } else if (xml.nodeType == 3) {
    // text
    obj = xml.nodeValue;
  }

  // do children
  if (xml.hasChildNodes()) {
    for (var i = 0; i < xml.childNodes.length; i++) {
      var item = xml.childNodes.item(i);
      var nodeName = item.nodeName;
      if (typeof obj[nodeName] == "undefined") {
        obj[nodeName] = xmlToJson(item);
      } else {
        if (typeof obj[nodeName].push == "undefined") {
          var old = obj[nodeName];
          obj[nodeName] = [];
          obj[nodeName].push(old);
        }
        obj[nodeName].push(xmlToJson(item));
      }
    }
  }
  return obj;
}

window.onresize = function () {
  app.resetPlayerUI();
};

app.connect();
